#include <iostream>
#include <unistd.h>
#include <pthread.h>

using namespace std;

#define TNUM 4

typedef void(*func_t)(const string& name, pthread_mutex_t* pmtx, pthread_cond_t* pcond);

class ThreadData
{
public: 
    ThreadData(const string& name, func_t func, pthread_mutex_t* pmtx, pthread_cond_t* pcond)
        :_name(name)
        ,_func(func)
        ,_pmtx(pmtx)
        ,_pcond(pcond)
    {}
public:
    string _name;
    func_t _func;
    pthread_mutex_t* _pmtx;
    pthread_cond_t* _pcond;
};

void func1(const string& name, pthread_mutex_t* pmtx, pthread_cond_t* pcond)
{
    while (true)
    {
        pthread_cond_wait(pcond, pmtx); // 运行到wait的时候，当前线程会立即被阻塞，每个线程都要这样做
        cout << name << " running..." << endl;
    }
}

void func2(const string& name, pthread_mutex_t* pmtx, pthread_cond_t* pcond)
{
    while (true)
    {
        pthread_cond_wait(pcond, pmtx);
        cout << name << " running..." << endl;
    }
}

void func3(const string& name, pthread_mutex_t* pmtx, pthread_cond_t* pcond)
{
    while (true)
    {
        pthread_cond_wait(pcond, pmtx);
        cout << name << " running..." << endl;
    }
}

void func4(const string& name, pthread_mutex_t* pmtx, pthread_cond_t* pcond)
{
    while (true)
    {
        pthread_cond_wait(pcond, pmtx);
        cout << name << " running..." << endl;
    }
}

void* Entry(void* args)
{
    ThreadData* td = (ThreadData*)args; // td在每一个线程私有的栈结构中保存
    td->_func(td->_name, td->_pmtx, td->_pcond);
    delete td; // 当函数执行完后也要释放td，因为它也是new出来的
}

int main()
{
    pthread_mutex_t mtx; // 互斥锁
    pthread_cond_t cond; // 条件变量

    // 初始化
    pthread_mutex_init(&mtx, nullptr);
    pthread_cond_init(&cond, nullptr);

    pthread_t tids[TNUM]; // 创建多线程
    func_t funcs[TNUM] = {func1, func2, func3, func4}; // 每个线程独有的方法
    for (int i = 0; i < TNUM; i++)
    {
        string name = "Thread ";
        name += to_string(i + 1);
        ThreadData* td = new ThreadData(name, funcs[i], &mtx, &cond);
        pthread_create(tids + i, nullptr, Entry, (void*)td);
    }

    // 让主线程区一个一个唤醒
    while (true)
    {
        sleep(1);
        cout << "resume thread run code: " << endl;
        pthread_cond_signal(&cond);

    }

    // 等待线程退出
    for (int i = 0; i < TNUM; i++)
    {
        pthread_join(tids[i], nullptr);
        cout << "thread: " << tids[i] << " quit" << endl;
    }

    // 销毁
    pthread_mutex_destroy(&mtx);
    pthread_cond_destroy(&cond);

    return 0;
}